package heap

import (
	"fmt"
	"hi-jvm/classfile"
)

type Constant interface{}

/*
运行时常量池
	主要存储两类信息：
		字面量（literal）： 整数，浮点数和字符串字面量
		符号引用（symbolic reference）： 符号引用，字段符号引用， 方法符号引用接口方法符号引用
 */
type ConstantPool struct {
	Class  *Class
	Consts []Constant
}

/*
根据索引放回常量
 */
func (self *ConstantPool) GetConstant(index uint) Constant {
	if c := self.Consts[index]; c != nil {
		return c
	}
	panic(fmt.Sprintf("No constants at index %d", index))
}

/*
把class文件中的常量池转换为运行时常量池
 */
func newConstantPool(class *Class, cfCp classfile.ConstantPool) *ConstantPool {
	cpCount := len(cfCp)
	consts := make([]Constant, cpCount)
	rtCp := &ConstantPool{class, consts}

	for i := 1; i < cpCount; i++ {
		cpInfo := cfCp[i]
		step, val := getClassConstant(cpInfo, rtCp)
		if step < 0 {
			continue
		}
		consts[i] = val
		if step > 0 {
			i += step
		}
	}

	return rtCp
}

func getClassConstant(cpInfo classfile.ConstantInfo, rtCp *ConstantPool) (step int, val Constant) {
	step = 0
	switch cpInfo.(type) {
	case *classfile.ConstantIntegerInfo:
		intInfo := cpInfo.(*classfile.ConstantIntegerInfo)
		val = intInfo.Val
		return
	case *classfile.ConstantFloatInfo:
		floatInfo := cpInfo.(*classfile.ConstantFloatInfo)
		val =  floatInfo.Val
		return
	case *classfile.ConstantLongInfo:
		longInfo := cpInfo.(*classfile.ConstantLongInfo)
		val =  longInfo.Val
		step = 1
		return
	case *classfile.ConstantDoubleInfo:
		doubleInfo := cpInfo.(*classfile.ConstantDoubleInfo)
		val = doubleInfo.Val
		step = 1
		return
	case *classfile.ConstantStringInfo:
		stringInfo := cpInfo.(*classfile.ConstantStringInfo)
		val = stringInfo.String()
		return
	case *classfile.ConstantClassInfo:
		classInfo := cpInfo.(*classfile.ConstantClassInfo)
		val = newClassRef(rtCp, classInfo)
		return
	case *classfile.ConstantFieldrefInfo:
		fieldrefInfo := cpInfo.(*classfile.ConstantFieldrefInfo)
		val = newFieldRef(rtCp, fieldrefInfo)
		return
	case *classfile.ConstantMethodrefInfo:
		methodrefInfo := cpInfo.(*classfile.ConstantMethodrefInfo)
		val = newMethodRef(rtCp, methodrefInfo)
		return
	case *classfile.ConstantInterfaceMethodrefInfo:
		methodrefInfo := cpInfo.(*classfile.ConstantInterfaceMethodrefInfo)
		val = newInterfaceMethodRef(rtCp, methodrefInfo)
		return
	default:
		// todo
		step = -1
		return
	}
}